package com.sina.interfaces.core.util;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.NumberSerializer;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.hibernate.SessionFactory;

import java.io.IOException;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.TimeZone;

/**
 * created  on 19/07/2017.
 */
public abstract class JsonUtils {


    /**
     * 用于将 form 内容以 json 形式输出
     */
    public static final ObjectMapper OBJECT_MAPPER;

    public static final LocalDateTimeDeserializer LOCALDATETIME_DESERIALIZER = new LocalDateTimeDeserializer(Constant.DATETIME_FORMATTER);

    public static final LocalDateTimeSerializer LOCALDATETIME_SERIALIZER = new LocalDateTimeSerializer(Constant.DATETIME_FORMATTER);

    public static final LocalDateDeserializer LOCALDATE_DESERIALIZER = new LocalDateDeserializer(Constant.DATE_FORMATTER);

    public static final LocalDateSerializer LOCALDATE_SERIALIZER = new LocalDateSerializer(Constant.DATE_FORMATTER);

    public static final NumberSerializer BIG_DECIMAL_NUMBER_SERIALIZER = new NumberSerializer(BigDecimal.class) {
        @Override
        public void serialize(Number value, JsonGenerator g, SerializerProvider provider) throws IOException {
            g.writeString(((BigDecimal) value).toPlainString());
        }
    };

    public static final NumberSerializer BIG_INTEGER_NUMBER_SERIALIZER = new NumberSerializer(BigInteger.class) {
        @Override
        public void serialize(Number value, JsonGenerator g, SerializerProvider provider) throws IOException {
            g.writeString(value.toString());
        }
    };

    public static final NumberSerializer LONG_NUMBER_SERIALIZER = new NumberSerializer(Long.class) {
        @Override
        public void serialize(Number value, JsonGenerator g, SerializerProvider provider) throws IOException {
            g.writeString(value.toString());
        }
    };

    /**
     * long 原型
     */
    public static final NumberSerializer LONG_TYPE_NUMBER_SERIALIZER = new NumberSerializer(Long.TYPE) {
        @Override
        public void serialize(Number value, JsonGenerator g, SerializerProvider provider) throws IOException {
            g.writeString(value.toString());
        }
    };


    static {
        OBJECT_MAPPER = createDefaultObjectMapper();
    }

    private JsonUtils() {

    }

    /**
     * 添加 java 8 时间特性({@link LocalDateTime}),并指定时区为东八区
     */
    public static ObjectMapper createDefaultObjectMapper(SessionFactory sessionFactory) {

        ObjectMapper mapper = new ObjectMapper();

        mapper.registerModule(createJavaTimeModule());

        mapper.registerModule(createCustomModule(null));

        mapper.registerModule(createHibernate5Module(sessionFactory));

        SimpleDateFormat format = new SimpleDateFormat(Constant.dateTimeFormat);
        format.setTimeZone(TimeZone.getTimeZone(Constant.timeZone8));
        mapper.setDateFormat(format);

        DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter();
        prettyPrinter.indentObjectsWith(new DefaultIndenter("  ", "\n"));
        mapper.setDefaultPrettyPrinter(prettyPrinter);
        return mapper;
    }


    public static ObjectMapper createDefaultObjectMapper() {
        return createDefaultObjectMapper(null);
    }

    private static Module createCustomModule(String moduleName) {
        // 自定义模块,重写部分序列化器
        return new SimpleModule(moduleName == null ? "InterfacesCustomModule" : moduleName)
                .addSerializer(BigDecimal.class, BIG_DECIMAL_NUMBER_SERIALIZER)
                .addSerializer(BigInteger.class, BIG_INTEGER_NUMBER_SERIALIZER)
                .addSerializer(Long.class, LONG_NUMBER_SERIALIZER)
                .addSerializer(Long.TYPE, LONG_TYPE_NUMBER_SERIALIZER)
                ;
    }

    private static Module createJavaTimeModule() {
        return new JavaTimeModule()
                .addDeserializer(LocalDateTime.class, LOCALDATETIME_DESERIALIZER)
                .addSerializer(LocalDateTime.class, LOCALDATETIME_SERIALIZER)

                .addDeserializer(LocalDate.class, LOCALDATE_DESERIALIZER)
                .addSerializer(LocalDate.class, LOCALDATE_SERIALIZER)
                ;
    }

    private static Module createHibernate5Module(SessionFactory sessionFactory) {
        return sessionFactory == null ? new Hibernate5Module() : new Hibernate5Module(sessionFactory);
    }

    public static String writeToJson(Object value) throws RuntimeException {
        return writeToJson(value, false);
    }

    public static String writeToJson(Object value, boolean pretty) throws RuntimeException {
        try {
            StringWriter writer = new StringWriter();
            JsonGenerator generator = OBJECT_MAPPER.getFactory().createGenerator(writer);
            if (pretty) {
                OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValue(generator, value);
            } else {
                OBJECT_MAPPER.writeValue(generator, value);
            }
            return writer.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


}
